﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "LineTypeDlg.h"

#include <QBoxLayout>
#include <QTableView>
#include <QHeaderView>
#include <QItemDelegate>
#include <QStandardItemModel>
#include <QPainter>
#include "GbmpNew.h"
#include "GmTitleBar.h"
#include "GmStyleSheetHelper.h"
#include "GbmpCommon.h"
#include "Vector3d.h"
#include "ILine3d.h"
#include "ILineTypeData.h"
#include "IUiDocumentViewManager.h"
#include "ILineTypeNew.h"
#include "IUiView.h"
#include "IUiDocument.h"
#include "IDocument.h"
#include "IUserTransaction.h"
#include "IElementAttributes.h"
#include "StringUtil.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

CREATE_DEBUG_MODE_EXPORT(UsingMonolinePreviewLineTypeFont, L"使用单线体展示线型文字", gcmp::DebugModeGroup::DMGT_RENDERING, L"GDMPLab", L"2023-12-20"
    , L"使用单线体展示线型文字, 需要把单线体字体yjkeng拷贝到bin\\font下");

const std::wstring s_product = L"product";
const std::wstring s_componentEditor = L"componentEditor";

namespace
{
    bool HasFontInfoInPatternString(const std::wstring& patternString)
    {
        if (patternString.empty()) {
            return false;
        }

       size_t bracketStart = patternString.find_first_of('[');
       size_t bracketEnd = patternString.find_first_of(']');
       if (std::wstring::npos != bracketStart || std::wstring::npos != bracketEnd) {
           return true;
       }
       return false;
    }

    double GetBasicLengthFromPatternString(const std::wstring& patternString)
    {
        DBG_WARN_AND_RETURN_UNLESS(!patternString.empty(), -1, L"为什么数据为空",L"GDMPLab",L"2024-03-30");

        std::vector<std::wstring> subStrs = StringUtil::SplitString(patternString, L",", true);
        if (subStrs.size() > 2 && subStrs.front() == L"A") {
            bool isOk = false;
            double length = StringUtil::ToNumber<double>(subStrs[1], &isOk);
            if (isOk) {
                return length;
            }
        }
        return -1;
    }

    double CalculateScale(const std::wstring& patternString)
    {
        double scale = -1;
        if (HasFontInfoInPatternString(patternString)) {
            double length = GetBasicLengthFromPatternString(patternString);
            if (length > 0)
            {
                scale = 40 / length;   // 40 为经验值
            }
        }
        return scale;
    }
}

IDocument* GetIDocument()
{
    IUiDocumentViewManager* pUiDocumentViewManager = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiDocumentViewManager, L"pUiDocumentViewManager为空",L"GDMPLab",L"2024-03-30");
    IUiView* pUIView = pUiDocumentViewManager->GetCurrentUiView();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUIView, L"pUIView为空",L"GDMPLab",L"2024-03-30");
    IUiDocument* pUIDoc = pUIView->GetUiDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUIDoc, L"pUIDoc为空",L"GDMPLab",L"2024-03-30");
    return  pUIDoc->GetDbDocument();
}

class DrawLineTypeDelegate : public QItemDelegate
{
public:
    DrawLineTypeDelegate(QObject *parent = 0)
        : QItemDelegate(parent)
    {
    }

    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        return nullptr;
    }

    void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
    {
        QItemDelegate::paint(painter, option, index);

        QPen pen;
        pen.setColor(Qt::black);
        pen.setWidth(1);
        painter->setPen(pen);

        // 构造待离散的预览直线
        double height = option.rect.top() + option.rect.bottom();
        double lineHeight = height * 0.5;
        OwnerPtr<ILine3d> lineToDiscrete = ILine3d::Create(Vector3d(option.rect.left(), lineHeight, 0.0), Vector3d(option.rect.right(), lineHeight, 0.0));

        // 通过线型名字，获得线型对象
        QModelIndex lineTypeNameIndex = index.sibling(index.row(), 0);
        std::wstring lineTypeName = lineTypeNameIndex.data().toString().toStdWString();
        IDocument* pDocument = GetIDocument();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pDocument, L"pDocument为空",L"GDMPLab",L"2024-03-30");
        const ILineTypeNew* pLineTypeEle = ILineTypeNew::GetLineTypeByName(pDocument, lineTypeName);
        if (!pLineTypeEle) return;
        const ILineTypeData* pLineType = pLineTypeEle->GetLineTypeData();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pLineType, L"pLineType为空",L"GDMPLab",L"2024-03-30");
        std::vector<Vector3d> vertexList, pointList, textTriangles;
        if (DEBUG_MODE(UsingMonolinePreviewLineTypeFont))
        {
            double scale = 10 /*CalculateScale(pLineType->GetPatternString()) */;
            pLineType->Discrete(lineToDiscrete.get(), scale, vertexList, pointList, textTriangles, L"yjkeng");
        }
        else
        {
            double scale = CalculateScale(pLineType->GetPatternString());
            pLineType->Discrete(lineToDiscrete.get(), scale, vertexList, pointList, textTriangles, L"");
        }


        if (!vertexList.empty())
        {
            for (int i = 0; i < (int)vertexList.size() - 1;)
            {
                painter->drawLine(QPointF(vertexList[i].X(), height -vertexList[i].Y()), QPointF(vertexList[i + 1].X(), height - vertexList[i + 1].Y()));
                i += 2;
            }
        }

        QVector<QPointF> qPointList;
        for each (auto& itr in pointList)
        {
            qPointList.push_back(QPointF(itr.X(), itr.Y()));
        }
        painter->drawPoints(qPointList);

        
        if (!textTriangles.empty())
        {
            painter->setRenderHint(QPainter::Antialiasing);
            painter->setRenderHint(QPainter::TextAntialiasing);
            for (size_t i = 0; i < textTriangles.size(); i = i + 3)
            {
                QPainterPath path;
                path.moveTo(QPointF(textTriangles[i].GetX(), height - textTriangles[i].GetY()));
                path.lineTo(QPointF(textTriangles[i + 1].GetX(), height - textTriangles[i + 1].GetY()));
                path.lineTo(QPointF(textTriangles[i + 2].GetX(), height - textTriangles[i + 2].GetY()));
                path.lineTo(QPointF(textTriangles[i].GetX(), height - textTriangles[i].GetY()));
                painter->drawPath(path);
            }
        }
        
    }
};
class EditDelegate : public QItemDelegate
{
public:
    EditDelegate(QObject *parent = 0)
        : QItemDelegate(parent)
    {

    }

    void setEditorData(QWidget *editor, const QModelIndex &index) const
    {
        // 名字应该都在第一列, 取得重命名前的名字
        QModelIndex nameIndex = index.sibling(index.row(), 0);
        QString oldLineTypeName = index.model()->data(nameIndex, Qt::UserRole/*目前使用UserRole*/).toString();
        IDocument* pDocument = GetIDocument();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pDocument, L"pDocument为空",L"GDMPLab",L"2024-03-30");
        ILineTypeNew* pLineTypeEle = ILineTypeNew::GetLineTypeByName(pDocument, oldLineTypeName.toStdWString());
        if (!pLineTypeEle)  return;
        const ILineTypeData* oldLineType = pLineTypeEle->GetLineTypeData();
        DBG_WARN_AND_RETURN_VOID_UNLESS(oldLineType, L"oldLineType为空",L"GDMPLab",L"2024-03-30");
        OwnerPtr<ILineTypeData> newLineType = oldLineType->Clone();
        DBG_WARN_AND_RETURN_VOID_UNLESS(newLineType, L"ILineTypeData克隆失败",L"GDMPLab",L"2024-03-30");

        // 新值
        bool valueChanged = false;
        QString value = index.model()->data(index, Qt::DisplayRole).toString();        
        if (index.column() == 0) //线型名字
        {
            if (value != oldLineTypeName)
            {
                newLineType->SetName(value.toStdWString());
                valueChanged = true;
                //备份线型名字
                const_cast<QAbstractItemModel*>(index.model())->setData(nameIndex, value, Qt::UserRole);
            }
        }
        else if (index.column() == 2) //线型模式
        {
            if (oldLineType->GetPatternString() != value.toStdWString())
            {
                newLineType->SetPatternString(value.toStdWString());
                valueChanged = true;
            }
        }

        if (valueChanged)
            pLineTypeEle->SetLineTypeData(TransferOwnership(newLineType));

        QItemDelegate::setEditorData(editor, index);
    }
};

LineTypeDlg::LineTypeDlg(QWidget *parent/* = nullptr*/)
    : QDialog(nullptr, Qt::FramelessWindowHint | Qt::WindowSystemMenuHint
        | Qt::WindowMinMaxButtonsHint)
{
    std::wstring styleSheetStr = GmStyleSheetHelper::Instance()->GetCurrentStyleData();
    setStyleSheet(QString::fromStdWString(styleSheetStr));
    
    this->setWindowTitle(QString::fromStdWString(GBMP_TR(L"线型管理")));

    //添加对象名
    this->setObjectName(QStringLiteral("LineTypeDlg"));

    m_dlgLayout = NEW_AS_QT_CHILD(QVBoxLayout, this);
    m_dlgLayout->setContentsMargins(0, 0, 0, 10);
    m_dlgLayout->setSpacing(6);
    setLayout(m_dlgLayout);
    GmTitleBar* pTitleBar = NEW_AS_QT_CHILD(GmTitleBar, this);
    pTitleBar->setObjectName(QStringLiteral("gbmp_title"));
    pTitleBar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
    pTitleBar->setIconVisible(false);
    pTitleBar->setMaxButtonVisible(false);
    pTitleBar->setMinButtonVisible(false);
    pTitleBar->setText(QString::fromStdWString(GBMP_TR(L"线型管理")));
    this->setProperty("use_gbmp_title", true);
    m_dlgLayout->addWidget(pTitleBar);

    CreateTableView();
    CreateButton();
    connect(pTitleBar, &GmTitleBar::closeRequested, this, &LineTypeDlg::reject);
    connect(pTitleBar, &GmTitleBar::moveRequested, this, &LineTypeDlg::onMoveRequested);
    this->resize(600, 600);

    IDocument* pDoc = GetIDocument();
    if (m_upUserTransaction == nullptr && !IUserTransaction::IsInUserTransaction(pDoc))
    {
        m_upUserTransaction = IUserTransaction::Create(pDoc, GBMP_TR(L"修改线型属性"));
    }
}

LineTypeDlg::~LineTypeDlg()
{

}

void LineTypeDlg::OnOK()
{
    QAbstractItemModel* pModel = m_tableView->model();
    int iRowIndex = m_tableView->currentIndex().row();
    if (iRowIndex >= 0)
    {
        m_selectLineTypeName = pModel->data(pModel->index(iRowIndex, 0)).toString();
    }
    else
    {
        m_selectLineTypeName = "";
    }

    if (m_upUserTransaction != nullptr)
    {
        m_upUserTransaction->Commit();
    }
    QDialog::accept();
}

void LineTypeDlg::CreateTableView()
{
    m_tableView = NEW_AS_QT_CHILD(QTableView, this);
    m_tableView->horizontalHeader()->setStretchLastSection(true);

    m_model = NEW_AS_QT_CHILD(QStandardItemModel, m_tableView);
    m_model->setHorizontalHeaderLabels(QStringList() << QString::fromStdWString(GBMP_TR(L"线型名称")) << QString::fromStdWString(GBMP_TR(L"线型样式")) << QString::fromStdWString(GBMP_TR(L"线型描述")));
    m_model->setHeaderData(0, Qt::Horizontal, QString::fromStdWString(GBMP_TR(L"线型名称")), Qt::AccessibleDescriptionRole);
    m_model->setHeaderData(1, Qt::Horizontal, QString::fromStdWString(GBMP_TR(L"线型样式")), Qt::AccessibleDescriptionRole);
    m_model->setHeaderData(2, Qt::Horizontal, QString::fromStdWString(GBMP_TR(L"线型描述")), Qt::AccessibleDescriptionRole);
    m_tableView->setModel(m_model);
    m_tableView->setColumnWidth(0, 100);
    m_tableView->setColumnWidth(1, 200);
    m_tableView->setColumnWidth(2, 100);

    m_tableView->setObjectName(QStringLiteral("LineTypeDlgTableView"));//添加对象名
    int rowIndex = 0;

    IDocument* pDoc = GetIDocument();
    if (m_upUserTransaction == nullptr && !IUserTransaction::IsInUserTransaction(pDoc))
    {
        m_upUserTransaction = IUserTransaction::Create(pDoc, GBMP_TR(L"修改线型属性"));
    }
    std::vector<ILineTypeNew*> lineTypes = ILineTypeNew::GetAllLineTypes(pDoc);
    // 按线型名称进行排序，否则界面出现乱序，日志回放的时候索引对应的线型不同，而造成脚本不过
    SortLineTypesByName(lineTypes);

    for each (auto& itr in lineTypes)
    {
        const IElement* pLineTypeElement = itr->GetOwnerElement();
        DBG_WARN_AND_CONTINUE_UNLESS(pLineTypeElement, L"pLineTypeElement为空",L"GDMPLab",L"2024-03-30");

        const IElementAttributes* pAttributes = pLineTypeElement->GetAttributes();
        DBG_WARN_AND_CONTINUE_UNLESS(pAttributes, L"pAttributes为空",L"GDMPLab",L"2024-03-30");

        std::wstring procuct;
        bool hasValue = pAttributes->GetAttributeValueAsString(s_product, procuct);
        if (hasValue && procuct == s_componentEditor)
        {
            continue;
        }

        const ILineTypeData* plnTypeData = itr->GetLineTypeData();
        gcmp::OwnerPtr<QStandardItem> nameItem = NEW_AS_OWNER_PTR(QStandardItem, QString::fromStdWString(plnTypeData->GetName()));

        // 利用Qt::UserRole，备份线型名字！！！！！重要！！！！
        nameItem->setData(QString::fromStdWString(plnTypeData->GetName()), Qt::UserRole);

        gcmp::OwnerPtr<QStandardItem> patternItem = NEW_AS_OWNER_PTR(QStandardItem, QString::fromStdWString(plnTypeData->GetPatternString()));

        QList<QStandardItem*> list;
        list.insert(list.end(), TRANSFER_OWNERSHIP_TO_THIRD_PARTY(nameItem));
        list.insert(list.end(), nullptr);
        list.insert(list.end(), TRANSFER_OWNERSHIP_TO_THIRD_PARTY(patternItem));

        m_model->appendRow(list);
        m_model->setHeaderData(rowIndex++, Qt::Vertical, QString::fromStdWString(plnTypeData->GetName()), Qt::AccessibleDescriptionRole);
    }

    static DrawLineTypeDelegate drawDelegate;
    m_tableView->setItemDelegateForColumn(1, &drawDelegate);
    m_tableView->verticalHeader()->setVisible(false);
    static EditDelegate editDelegate;
    m_tableView->setItemDelegate(&editDelegate);
    QHBoxLayout* pTabelLayout = NEW_AS_QT_LAYOUT(QHBoxLayout);
    pTabelLayout->addWidget(m_tableView);
    pTabelLayout->setContentsMargins(10, 4, 10, 6);
    m_dlgLayout->addLayout(pTabelLayout);

}

void LineTypeDlg::CreateButton()
{
    gcmp::OwnerPtr<QWidget> buttonWidget = NEW_AS_OWNER_PTR(QWidget);
    //添加对象名
    buttonWidget->setObjectName(QStringLiteral("buttonWidget"));

    gcmp::OwnerPtr<QPushButton> okButton = NEW_AS_OWNER_PTR(QPushButton);
    okButton->setText(QString::fromStdWString(GBMP_TR(L"确认")));
    okButton->setBaseSize(QSize(100, 50));
    //添加对象名
    okButton->setObjectName(QStringLiteral("LineTypeDlgOkButton"));
    connect(okButton.get(), SIGNAL(clicked()), this, SLOT(OnOK()));
    gcmp::OwnerPtr<QPushButton> cancelButton = NEW_AS_OWNER_PTR(QPushButton);
    cancelButton->setText(QString::fromStdWString(GBMP_TR(L"取消")));
    cancelButton->setObjectName(QStringLiteral("cancelButton"));
    gcmp::OwnerPtr<QSpacerItem> pSpacer = NEW_AS_OWNER_PTR(QSpacerItem, 20, 20, QSizePolicy::Expanding);
    connect(cancelButton.get(), SIGNAL(clicked()), this, SLOT(OnCancle()));
    gcmp::OwnerPtr<QHBoxLayout> buttonLayout = NEW_AS_OWNER_PTR(QHBoxLayout);
    buttonLayout->setContentsMargins(0, 0, 10, 0);
    buttonLayout->addItem(TRANSFER_OWNERSHIP_TO_THIRD_PARTY(pSpacer));
    buttonLayout->addWidget(TRANSFER_OWNERSHIP_TO_THIRD_PARTY(okButton));
    buttonLayout->addWidget(TRANSFER_OWNERSHIP_TO_THIRD_PARTY(cancelButton));
    buttonWidget->setLayout(TRANSFER_OWNERSHIP_TO_THIRD_PARTY(buttonLayout));
    m_dlgLayout->addWidget(TRANSFER_OWNERSHIP_TO_THIRD_PARTY(buttonWidget));
}

void LineTypeDlg::OnCancle()
{
    if (m_upUserTransaction != nullptr)
    {
        m_upUserTransaction->Rollback();
    }

    QDialog::reject();
}

void LineTypeDlg::onMoveRequested(const QPoint& cursorPos, const QPoint& offset)
{
    Q_UNUSED(cursorPos);
    move(pos() + offset);
}

// 按线型名称进行排序
void LineTypeDlg::SortLineTypesByName(std::vector<ILineTypeNew*>& arrLineTypes) const
{
    auto CompareLineNameFunc = [](const ILineTypeNew* pVal1, const ILineTypeNew* pVal2) -> bool
    {
        DBG_WARN_AND_RETURN_UNLESS(pVal1, false, L"pVal1为空",L"GDMPLab",L"2024-03-30");
        DBG_WARN_AND_RETURN_UNLESS(pVal2, true, L"pVal2为空",L"GDMPLab",L"2024-03-30");
        const ILineTypeData* pData1 = pVal1->GetLineTypeData();
        const ILineTypeData* pData2 = pVal2->GetLineTypeData();
        DBG_WARN_AND_RETURN_UNLESS(pData1, false, L"pData1为空",L"GDMPLab",L"2024-03-30");
        DBG_WARN_AND_RETURN_UNLESS(pData2, true, L"pData2为空",L"GDMPLab",L"2024-03-30");

        return pData1->GetName() < pData2->GetName();
    };
    std::sort(arrLineTypes.begin(), arrLineTypes.end(), CompareLineNameFunc);
}